/*****************************************
此模块是除法开方模块，计算使用srt4算法进行除法开方运算，
支持单精度数和双精度数，
此模块的功能：输入两个单精度或者双精度数，输出除法结果，相应指令为FDIV.d   FDIV.s   
             输入一个单精度或者双精度数，输出开方结果, 相应指令为FSQRT.d  FSQRT.s
             计算rs1 / rs2

*****************************************/
module fp_div_sqrt_top(
    input        clk        ,
    input        rst_n      ,

    //控制逻辑
    input                   req        ,       //运算请求
    input                   cancel     ,       //运算取消
    input       [1:0]       opcode     ,       //执行哪种指令 00:FDIV.d 01:FDIV.s 10:FSQRT.d 11:FSQRT.s 

    //舍入模式 IEEE754-2008 000:RNZ, round to nearest even  就近偶舍入
    //                      001:RTZ, round to turncation  截断，向零舍入
    //                      010:RDN, round to minus infinity  向负无穷舍入
    //                      011:rup, round to positive infinity  向正无穷舍入
    //                      100:RMM, round to nearest odd    远离零舍入
    input       [2:0]       round_mode ,       


    //数据输入
    input       [64-1:0]      rs1         ,       //操作数1
    input       [64-1:0]      rs2         ,       //操作数2

    //运算数据输出
    output      [5:0]       status      ,       //特殊值
    output                  available   ,       //可以接收新的计算数据
    output                  finish      ,       //结果运算好输出
    output      [63:0]      result              //结果
             
);

//parameter dp_pzero = 64'h0;
//parameter dp_nzero = 64'h8000000000000000;
//parameter dp_qnan = {1'bx, 11'hFFF, 1'b1, 51{1'bx}};
//parameter dp_snan = {1'bx, 11'hFFF, 1'b0, != 0 };
//parameter dp_pinfinity = 64'h7FF0000000000000;
//parameter dp_ninfinity = 64'hFFF0000000000000;

//浮点数拆分
wire                        rs1_sign    ;
wire        [11-1:0]        rs1_exp     ;
wire        [52-1:0]        rs1_tail    ;

wire                        rs2_sign    ;
wire        [11-1:0]        rs2_exp     ;
wire        [52-1:0]        rs2_tail    ;

//特殊值判断
wire                        rs1_dp_zero     ;
wire                        rs1_dp_nan      ;
wire                        rs1_dp_infinity ;

wire                        rs2_dp_zero     ;
wire                        rs2_dp_nan      ;
wire                        rs2_dp_infinity ;

//补全后的尾数定义
wire        [53-1:0]        rs1_dp_tail     ;
wire        [53-1:0]        rs2_dp_tail     ;

//除法开方指示信号，单双精度指示信号
wire                        fdiv_fsqrt      ;       //1:除法       0:开方
wire                        signal_double   ;       //1:单精度     0:双精度

//指数计算模块输出的中间指数
wire        [12-1:0]        middle_exp      ;       //1位符号位，11位有效位

//on-the-fly转换算法信号定义
wire        [53-1:0]        a               ;
wire        [53-1:0]        b               ;
wire        [53-1:0]        a_next          ;
wire        [53-1:0]        b_next          ;
wire        [3-1:0]         q_i             ;

//操作数1 的特殊值判断
assign rs1_dp_zero = rs1[62:0] == 63'h0 ? 1'b1 : 1'b0 ; //rs1 == 0   ? 1 : 0
assign rs1_dp_nan = rs1[62:52] == 11'hFFF ? (rs1[51:0] != 52'b0 ? 1'b1 : 1'b0) : 1'b0 ;  //rs1 == nan ? 1 : 0
assign rs1_dp_infinity = rs1[62:52] == 11'hFFF ? ( rs1[51:0] == 52'h0 ? 1'b1 : 1'b0 ) : 1'b0 ;  // rs1 == inf ? 1 : 0

//操作数2 的特殊值判断
assign rs2_dp_zero = rs2[62:0] == 63'h0 ? 1'b1 : 1'b0 ; //rs2 == 0   ? 1 : 0
assign rs2_dp_nan = rs2[62:52] == 11'hFFF ? (rs2[51:0] != 52'b0 ? 1'b1 : 1'b0) : 1'b0 ;  //rs2 == nan ? 1 : 0
assign rs2_dp_infinity = rs2[62:52] == 11'hFFF ? ( rs2[51:0] == 52'h0 ? 1'b1 : 1'b0 ) : 1'b0 ;  // rs2 == inf ? 1 : 0

//操作数1 拆分
assign rs1_sign = rs1[63]   ;
assign rs1_exp = rs1[62:52] ;
assign rs1_tail = rs1[51:0] ;    

//操作数2 拆分
assign rs2_sign = rs2[63]   ;
assign rs2_exp = rs2[62:52] ;
assign rs2_tail = rs2[51:0] ; 
    
//根据指数判断是否是非规格化数，将隐藏位补全
assign rs1_dp_tail = rs1_exp == 11'h0 ? {1'b0, rs1_tail} : {1'b1, rs1_tail};
assign rs2_dp_tail = rs2_exp == 11'h0 ? {1'b0, rs2_tail} : {1'b1, rs2_tail};

//区分是除法运算还是开方运算
assign fdiv_fsqrt = opcode[1] == 1'b0 ? 1'b1 : 1'b0 ;    //1:除法   0:开方
assign signal_double = opcode[0] == 1'b1 ? 1'b1 : 1'b0 ;   // 1:单精度    0:双精度

//调用指数处理模块
exp_handle u_exp_handle(  
    .code(fdiv_fsqrt)                   ,   //1:除法   0:开方
    .exp1(rs1_exp)                      ,   //操作数1的指数
    .exp2(rs2_exp)                      ,   //操作数2的指数
    .signal_double(signal_double)       ,   // 1:单精度    0:双精度
    .exp_out(middle_exp)                    //输出的指数

);

//调用尾数处理模块，组合逻辑，每回迭代一次
div_sqrt u_div_sqrt(
    .x              ()         ,   //被除数
    .d              ()         ,   //除数
    .sqrt_j         ()         ,   //输入的部分开方值，用于开方迭代
    .div_or_sqrt    ()         ,   //指示是除法还是开方 1：div 0:sqrt

    .q              ()         ,   //商数字q，除法就代表商，开方就代表平方根
    .rw             ()         ，  //部分余数
    .sqrt_j_53      ()             //全长的部分开方值
);

/*************************
on-the-fly转换算法
A = {A， q}                if q >= 0
  = {B, r - |q|}           if q <  0

B = {A, q-1}               if q >  0
  = {B, {(r - 1) - |q|} }  if q <= 0

q=010，表示2

q=001，表示1

q=000，表示0

q=111，表示-1

q=110，表示-2
**************************/
assign a_next = ~q_i[2]              ? {a[53-3:0], q_i[1:0]} :
                                       {b[53-3:0], q_i[1:0]} ;
assign b_next = ~q_i[2] &(|q_i[1:0]) ? {a[53-3:0], q_i[2:1]} :
                                       {b[53-3:0], {q_i[1]^~q[0], ~q_i[0] }};

endmodule